import os
import shutil
import subprocess
import sys
import threading
import zipfile

import requests
from PySide6.QtWidgets import QMessageBox, QProgressDialog

from config import APP_VERSION, get_new_version_url, VERSION_URL, BASE_PATH
from utils.common import get_value_from_text
from utils.signal_emitter import UpdateSignalEmitter


class UpdateProgress:

    def __init__(self, app):
        super().__init__()
        self.progress_dialog = None
        self.app = app
        self.download_path = ''
        self.update_folder = ''

    def update_process(self, total_size, block_size, downloaded_size):
        if total_size == 1:
            self.execute_update()

        elif total_size == -1:
            QMessageBox.critical(None, "Cancel", "The user canceled the update file download.")
            return
        elif total_size == -2:
            QMessageBox.critical(None, "Error", f"Unable to download update file")
            return
        elif total_size == -3:
            QMessageBox.critical(None, "Error", f"An error occurred while downloading the update file")
            return

        if downloaded_size == -1:
            self.progress_dialog = QProgressDialog("Downloading...", "Cancel", 0, total_size / block_size)
            self.progress_dialog.setWindowTitle("Download Progress")
            self.progress_dialog.setFixedSize(350, 175)
            self.progress_dialog.setMinimumDuration(0)
        elif downloaded_size != 0:
            self.progress_dialog.setValue(downloaded_size / block_size)


    def prompt_user_to_update(self, update_info):
        server_version = get_value_from_text(update_info, 'APP_VERSION')
        msg_box = QMessageBox()
        msg_box.setIcon(QMessageBox.Information)
        msg_box.setText(f"There is a new version available: {server_version}")
        msg_box.setInformativeText(get_value_from_text(update_info, 'UPDATE_INFO'))
        msg_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
        msg_box.setDefaultButton(QMessageBox.Yes)
        result = msg_box.exec()

        if result == QMessageBox.Yes:
            update_signal = UpdateSignalEmitter()
            update_signal.result_signal.connect(self.update_process)
            self.download_path = os.path.join(BASE_PATH, f"update_{server_version}.zip")
            download_thread = threading.Thread(target=self.download_file,
                                               args=(server_version, update_signal))
            download_thread.start()

    def download_file(self, server_version, update_signal):
        try:
            url = get_new_version_url(server_version)
            response = requests.get(url, stream=True, verify=False)
            if response.status_code == 200:
                total_size = int(response.headers.get('content-length', 0))
                block_size = 1024
                update_signal.result_signal.emit(int(total_size), block_size, -1)

                with open(self.download_path, "wb") as f:
                    downloaded_size = 0
                    for chunk in response.iter_content(chunk_size=block_size):
                        f.write(chunk)
                        downloaded_size += len(chunk)
                        update_signal.result_signal.emit(total_size, block_size, downloaded_size)
                        if self.progress_dialog.wasCanceled():
                            break

                if not self.progress_dialog.wasCanceled():
                    with zipfile.ZipFile(self.download_path, 'r') as zip_ref:
                        self.update_folder = os.path.join(BASE_PATH, "update_folder")
                        update_signal.result_signal.emit(2, 0, 0)
                        # 如果文件夹存在，则删除
                        if os.path.exists(self.update_folder):
                            shutil.rmtree(self.update_folder)
                        zip_ref.extractall(self.update_folder)
                    update_signal.result_signal.emit(1, 0, 0)
                    self.download_path = self.download_path
                else:
                    os.remove(self.download_path)
                    update_signal.result_signal.emit(-1, 0, 0)

            else:
                update_signal.result_signal.emit(-2, 0, 0)
        except requests.exceptions.RequestException as e:
            update_signal.result_signal.emit(-3, 0, 0)

    def execute_update(self):
        try:
            # 假设解压后的文件夹中有一个可执行文件或更新脚本，这里替换旧的程序文件
            old_program_path = BASE_PATH
            app_name = "Fu Reader.exe"

            new_program_path = os.path.join(self.update_folder, app_name)
            old_bak_path = os.path.join(old_program_path, "old.bak")
            print("old_bak_path", old_bak_path)
            print("new_program_path", new_program_path)
            print("download_path", self.download_path)
            print("update_folder", self.update_folder)

            if os.path.exists(old_bak_path):
                os.remove(old_bak_path)
            os.rename(os.path.join(old_program_path, app_name), old_bak_path)
            shutil.move(new_program_path, old_program_path)

            if os.path.exists(new_program_path):
                shutil.rmtree(self.update_folder)
            if os.path.exists(self.download_path):
                os.remove(self.download_path)

            msg_box = QMessageBox()
            msg_box.setIcon(QMessageBox.Information)
            msg_box.setText(f"Update Successfully")
            msg_box.setInformativeText("Do you want to restart the update?")
            msg_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
            msg_box.setDefaultButton(QMessageBox.Yes)
            result = msg_box.exec()
            if result == QMessageBox.Yes:
                os.system(f"taskkill /f /im \"{app_name}\"")
            # self.app.quit()
            # os.startfile(os.path.join(old_program_path, app_name))  # 替换为你的主程序名
        except Exception as e:
            QMessageBox.critical(None, "The update failed", f"An error occurred while performing the update: {e}")

    def check_for_updates(self):
        try:
            response = requests.get(VERSION_URL, verify=False)
            if response.status_code == 200:
                update_info = response.text
                server_version = get_value_from_text(update_info, "APP_VERSION")
                if self.compare_versions(server_version, APP_VERSION):
                    self.prompt_user_to_update(update_info)
                else:
                    QMessageBox.information(None, "Tip", f"The version {APP_VERSION} is already the latest.")
            return None
        except requests.exceptions.RequestException as e:
            print(f"检查更新时出错: {e}")
            return None

    def compare_versions(self, server_version, local_version):
        server_parts = server_version.split(".")
        local_parts = local_version.split(".")

        for i in range(len(server_parts)):
            if int(server_parts[i]) > int(local_parts[i]):
                return True
            elif int(server_parts[i]) < int(local_parts[i]):
                return False

        return False